package com.zj.ffmpeg;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.List;

import com.zj.entity.Camera;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.HexUtil;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class FFmpeg {
	
	/**
	 * ws客户端
	 */
//	private ConcurrentHashMap<String, ChannelHandlerContext> wsClients = new ConcurrentHashMap<>();
//	/**
//	 * http客户端
//	 */
//	private ConcurrentHashMap<String, ChannelHandlerContext> httpClients = new ConcurrentHashMap<>();

	/**
	 * flv header
	 */
	private byte[] header = null;
	/**
	 * 相机
	 */
	private Camera camera;

	private List<String> command = new ArrayList<>();

	private ServerSocket tcpServer = null;

	private Process process;
	private Thread inputThread;
	private Thread errThread;
	private boolean running = false;	//启动
	private boolean outputStatus = false;		//输出
	private boolean enableLog = false;

	public FFmpeg(final String executable) {
		command.add(executable);
	}

	public FFmpeg addArgument(String argument) {
		command.add(argument);
		return this;
	}

	public FFmpeg execute() {
		String output = getOutput();
		command.add(output);

		String join = CollUtil.join(command, " ");
		log.info(join);
		try {
			process = new ProcessBuilder(command).start();
			running = true;
			dealStream(process);
			outputData();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return this;
	}

	public void outputData() {
		Socket client = null;
		try {
			client = tcpServer.accept();
			outputStatus = true;
			DataInputStream input = new DataInputStream(client.getInputStream());

			byte[] buffer = new byte[1024];
			int len = 0;
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			while (outputStatus) {
				len = input.read(buffer);
				if(len == -1) {
					break;
				}
				
				bos.write(buffer, 0, len);
				
				if (header == null) {
					header = bos.toByteArray();
//					System.out.println(HexUtil.encodeHexStr(header));
					bos.reset();
					continue;
				}
				
				System.out.println(HexUtil.encodeHexStr(bos.toByteArray()));
				bos.reset();
			}

		} catch (SocketTimeoutException e1) {
//			e1.printStackTrace();
//			超时关闭
		} catch (IOException e) {
//			e.printStackTrace();
		} finally {
			running = false;
			process.destroy();
			try {
				if(null != client) {
					client.close();
				}
			} catch (IOException e) {
			}
			try {
				if(null != tcpServer) {
					tcpServer.close();
				}
			} catch (IOException e) {
			}
		}
	}

	public static FFmpeg atPath() {
		return atPath(null);
	}

	public static FFmpeg atPath(final String absPath) {
		final String executable;
		if (absPath != null) {
			executable = absPath;
		} else {
			executable = "ffmpeg";
		}
		return new FFmpeg(executable);
	}

	public void dealStream(Process process) {
		if (process == null) {
			return;
		}
		// 处理InputStream的线程
		inputThread = new Thread() {
			@Override
			public void run() {
				BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
				String line = null;
				try {
					while (running) {
						line = in.readLine();
						if (line == null) {
							break;
						}
						if(enableLog) {
							log.info("output: " + line);
						}
					}
				} catch (IOException e) {
					e.printStackTrace();
				} finally {
					try {
						in.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		};
		// 处理ErrorStream的线程
		errThread = new Thread() {
			@Override
			public void run() {
				BufferedReader err = new BufferedReader(new InputStreamReader(process.getErrorStream()));
				String line = null;
				try {
					while (running) {
						line = err.readLine();
						if (line == null) {
							break;
						}
						if(enableLog) {
							log.info("err: " + line);
						}
					}
				} catch (IOException e) {
					e.printStackTrace();
				} finally {
					try {
						err.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		};

		inputThread.start();
		errThread.start();
	}

	private String getOutput() {
		try {
			tcpServer = new ServerSocket(0, 1, InetAddress.getLoopbackAddress());
			StringBuffer sb = new StringBuffer();
			sb.append("tcp://");
			sb.append(tcpServer.getInetAddress().getHostAddress());
			sb.append(":");
			sb.append(tcpServer.getLocalPort());
			tcpServer.setSoTimeout(10000);
			return sb.toString();
		} catch (IOException e) {
			e.printStackTrace();
		}
		new RuntimeException("无法启用端口");
		return "";
	}

	public static void main(String[] args) throws Exception {
//		ServerSocket serverSocket = new ServerSocket(0, 1, InetAddress.getLoopbackAddress());
//		System.out.println(serverSocket.getLocalPort());
//		System.out.println(serverSocket.getInetAddress().getHostAddress());

//		FFmpeg.atPath().addInput("-i rtsp://admin:VZCDOY@192.168.2.84:554/Streaming/Channels/102").addArgument("-g 5 -c:v libx264 -c:a aac -f flv").executeAsync();
//		FFmpeg.atPath().addInput("-i rtsp://admin:VZCDOY@192.168.2.84:554/Streaming/Channels/102").addArgument("-g 5 -c:v libx264 -c:a aac -f flv").addOutput("tcp://localhost:55444").executeAsync();
		FFmpeg.atPath().addArgument("-i").addArgument("rtsp://admin:VZCDOY@192.168.2.84:554/Streaming/Channels/102")
				.addArgument("-g").addArgument("5").addArgument("-c:v").addArgument("libx264").addArgument("-c:a")
				.addArgument("aac").addArgument("-f").addArgument("flv").execute();
	}

}
